using System.Diagnostics;

namespace Tab2Sql
{

	using u8 = System.Byte;

	public partial class Sqlite3
	{
		static byte[] sqlite3CtypeMap = new byte[] {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 00..07    ........ */
  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
  0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,  /* 20..27     !"#$%&' */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,  /* 30..37    01234567 */
  0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 38..3f    89:;<=>? */

  0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02,  /* 40..47    @ABCDEFG */
  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 48..4f    HIJKLMNO */
  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 50..57    PQRSTUVW */
  0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
  0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 68..6f    hijklmno */
  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 70..77    pqrstuvw */
  0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 78..7f    xyz{|}~. */

  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 80..87    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 88..8f    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 90..97    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 98..9f    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* a0..a7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* a8..af    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* b0..b7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* b8..bf    ........ */

  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* c0..c7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* c8..cf    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d0..d7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d8..df    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
		};
		static int[] sqlite3UpperToLower = new int[]  {
0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 0x */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */

};
		static int[] UpperToLower=sqlite3UpperToLower;
		/*
    ** 2001 September 15
    **
    ** The author disclaims copyright to this source code.  In place of
    ** a legal notice, here is a blessing:
    **
    **    May you do good and not evil.
    **    May you find forgiveness for yourself and forgive others.
    **    May you share freely, never taking more than you give.
    **
    *************************************************************************
    ** An tokenizer for SQL
    **
    ** This file contains C code that implements the sqlite3_complete() API.
    ** This code used to be part of the tokenizer.c source file.  But by
    ** separating it out, the code will be automatically omitted from
    ** static links that do not use it.
    *************************************************************************
    **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
    **  C#-SQLite is an independent reimplementation of the SQLite software library
    **
    **  SQLITE_SOURCE_ID: 2010-03-09 19:31:43 4ae453ea7be69018d8c16eb8dabe05617397dc4d
    **
    **  $Header$
    *************************************************************************
    */
		//#include "sqliteInt.h"


/*
** This is defined in tokenize.c.  We just have to import the definition.
*/		
		
		//#define IdChar(C)  ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
				static bool IdChar (u8 C)
		{
			return (sqlite3CtypeMap[(char)C] & 0x46) != 0;
		}

//extern const char sqlite3IsEbcdicIdChar[];
//#define IdChar(C)  (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))

		/*
** Token types used by the sqlite3_complete() routine.  See the header
** comments on that procedure for additional information.
*/
		const int tkSEMI = 0;
		const int tkWS = 1;
		const int tkOTHER = 2;
		const int tkEXPLAIN = 3;
		const int tkCREATE = 4;
		const int tkTEMP = 5;
		const int tkTRIGGER = 6;
		const int tkEND = 7;


		/*
** Return TRUE if the given SQL string ends in a semicolon.
**
** Special handling is require for CREATE TRIGGER statements.
** Whenever the CREATE TRIGGER keywords are seen, the statement
** must end with ";END;".
**
** This implementation uses a state machine with 8 states:
**
**   (0) INVALID   We have not yet seen a non-whitespace character.
**
**   (1) START     At the beginning or end of an SQL statement.  This routine
**                 returns 1 if it ends in the START state and 0 if it ends
**                 in any other state.
**
**   (2) NORMAL    We are in the middle of statement which ends with a single
**                 semicolon.
**
**   (3) EXPLAIN   The keyword EXPLAIN has been seen at the beginning of 
**                 a statement.
**
**   (4) CREATE    The keyword CREATE has been seen at the beginning of a
**                 statement, possibly preceeded by EXPLAIN and/or followed by
**                 TEMP or TEMPORARY
**
**   (5) TRIGGER   We are in the middle of a trigger definition that must be
**                 ended by a semicolon, the keyword END, and another semicolon.
**
**   (6) SEMI      We've seen the first semicolon in the ";END;" that occurs at
**                 the end of a trigger definition.
**
**   (7) END       We've seen the ";END" of the ";END;" that occurs at the end
**                 of a trigger difinition.
**
** Transitions between states above are determined by tokens extracted
** from the input.  The following tokens are significant:
**
**   (0) tkSEMI      A semicolon.
**   (1) tkWS        Whitespace.
**   (2) tkOTHER     Any other SQL token.
**   (3) tkEXPLAIN   The "explain" keyword.
**   (4) tkCREATE    The "create" keyword.
**   (5) tkTEMP      The "temp" or "temporary" keyword.
**   (6) tkTRIGGER   The "trigger" keyword.
**   (7) tkEND       The "end" keyword.
**
** Whitespace never causes a state transition and is always ignored.
** This means that a SQL string of all whitespace is invalid.
**
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
** to recognize the end of a trigger can be omitted.  All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
static int sqlite3StrNICmp( string zLeft, int offsetLeft, string zRight, int N )
    {
      //register unsigned char *a, *b;
      //a = (unsigned char *)zLeft;
      //b = (unsigned char *)zRight;
      int a = 0, b = 0;
      while ( N-- > 0 && a < zLeft.Length - offsetLeft && b < zRight.Length && zLeft[a + offsetLeft] != 0 && UpperToLower[zLeft[a + offsetLeft]] == UpperToLower[zRight[b]] ) { a++; b++; }
      return N < 0 ? 0 : UpperToLower[zLeft[a + offsetLeft]] - UpperToLower[zRight[b]];
    }

    static int sqlite3StrNICmp( string zLeft, string zRight, int N )
    {
      //register unsigned char *a, *b;
      //a = (unsigned char *)zLeft;
      //b = (unsigned char *)zRight;
      int a = 0, b = 0;
      while ( N-- > 0 && a < zLeft.Length && b < zRight.Length && ( zLeft[a] == zRight[b] || ( zLeft[a] != 0 && zLeft[a] < 256 && zRight[b] < 256 && UpperToLower[zLeft[a]] == UpperToLower[zRight[b]] ) ) ) { a++; b++; }
      if ( N < 0 ) return 0;
      if ( a == zLeft.Length && b == zRight.Length ) return 0;
      if ( a == zLeft.Length ) return -UpperToLower[zRight[b]];
      if ( b == zRight.Length ) return UpperToLower[zLeft[a]];
      return ( zLeft[a] < 256 ? UpperToLower[zLeft[a]] : zLeft[a] ) - ( zRight[b] < 256 ? UpperToLower[zRight[b]] : zRight[b] );
    }

		public static int sqlite3_complete (string zSql)
		{
			int state = 0;
			/* Current state, using numbers defined in header comment */			int token;
			/* Value of the next token */			
						/* A complex statement machine used to detect the end of a CREATE TRIGGER
** statement.  This is the normal case.
*/
u8[][] trans = new u8[][] { 			/* Token:                                                */
			/* State:       **  SEMI  WS  OTHER  EXPLAIN  CREATE  TEMP  TRIGGER  END */
			/* 0 INVALID: */new u8[] { 1, 0, 2, 3, 4, 2, 2, 2 }, 			/* 1   START: */new u8[] { 1, 1, 2, 3, 4, 2, 2, 2 }, 			/* 2  NORMAL: */new u8[] { 1, 2, 2, 2, 2, 2, 2, 2 }, 			/* 3 EXPLAIN: */new u8[] { 1, 3, 3, 2, 4, 2, 2, 2 }, 			/* 4  CREATE: */new u8[] { 1, 4, 2, 2, 2, 4, 5, 2 }, 			/* 5 TRIGGER: */new u8[] { 6, 5, 5, 5, 5, 5, 5, 5 }, 			/* 6    SEMI: */new u8[] { 6, 6, 5, 5, 5, 5, 5, 7 }, 			/* 7     END: */new u8[] { 1, 7, 5, 5, 5, 5, 5, 5 } };
			
						/* If triggers are not supported by this compile then the statement machine
  ** used to detect the end of a statement is much simplier
  */
trans = new u8[][] { 			/* Token:           */
			/* State:       **  SEMI  WS  OTHER */
			/* 0 INVALID: */new u8[] { 1, 0, 2 }, 			/* 1   START: */new u8[] { 1, 1, 2 }, 			/* 2  NORMAL: */new u8[] { 1, 2, 2 } };
			
			
			int zIdx = 0;
			while (zIdx < zSql.Length) {
				switch (zSql[zIdx]) {
				case ';':
					
					{
						/* A semicolon */						token = tkSEMI;
						break;
					}

				case ' ':
				case '\r':
				case '\t':
				case '\n':
				case '\f':
					
					{
						/* White space is ignored */						token = tkWS;
						break;
					}

				case '/':
					
					{
						/* C-style comments */						if (zSql[zIdx + 1] != '*') {
							token = tkOTHER;
							break;
						}
						zIdx += 2;
						while (zIdx < zSql.Length && zSql[zIdx] != '*' || zIdx < zSql.Length - 1 && zSql[zIdx + 1] != '/') {
							zIdx++;
						}
						if (zIdx == zSql.Length)
							return 0;
						zIdx++;
						token = tkWS;
						break;
					}

				case '-':
					
					{
						/* SQL-style comments from "--" to end of line */						if (zSql[zIdx + 1] != '-') {
							token = tkOTHER;
							break;
						}
						while (zIdx < zSql.Length && zSql[zIdx] != '\n') {
							zIdx++;
						}
						if (zIdx == zSql.Length)
							return state == 1 ? 1 : 0;
						//if( *zSql==0 ) return state==1;
						token = tkWS;
						break;
					}

				case '[':
					
					{
						/* Microsoft-style identifiers in [...] */						zIdx++;
						while (zIdx < zSql.Length && zSql[zIdx] != ']') {
							zIdx++;
						}
						if (zIdx == zSql.Length)
							return 0;
						token = tkOTHER;
						break;
					}

				case '`':
				case 				/* Grave-accent quoted symbols used by MySQL */'"':
				case 				/* single- and double-quoted strings */'\'':
					
					{
						int c = zSql[zIdx];
						zIdx++;
						while (zIdx < zSql.Length && zSql[zIdx] != c) {
							zIdx++;
						}
						if (zIdx == zSql.Length)
							return 0;
						token = tkOTHER;
						break;
					}

				default:
					
					{
						char c;
						if (IdChar ((u8)zSql[zIdx])) {
							/* Keywords and unquoted identifiers */							
							int nId;
							for (nId = 1; (zIdx + nId) < zSql.Length && IdChar ((u8)zSql[zIdx + nId]); nId++) {
							}
							
							token = tkOTHER;
							
							switch (zSql[zIdx]) {
							case 'c':
							case 'C':
								
								{
									if (nId == 6 && sqlite3StrNICmp (zSql, zIdx, "create", 6) == 0) {
										token = tkCREATE;
									} else {
										token = tkOTHER;
									}
									break;
								}

							case 't':
							case 'T':
								
								{
									if (nId == 7 && sqlite3StrNICmp (zSql, zIdx, "trigger", 7) == 0) {
										token = tkTRIGGER;
									} else if (nId == 4 && sqlite3StrNICmp (zSql, zIdx, "temp", 4) == 0) {
										token = tkTEMP;
									} else if (nId == 9 && sqlite3StrNICmp (zSql, zIdx, "temporary", 9) == 0) {
										token = tkTEMP;
									} else {
										token = tkOTHER;
									}
									break;
								}

							case 'e':
							case 'E':
								
								{
									if (nId == 3 && sqlite3StrNICmp (zSql, zIdx, "end", 3) == 0) {
										token = tkEND;
									} else if (nId == 7 && sqlite3StrNICmp (zSql, zIdx, "explain", 7) == 0) {
										token = tkEXPLAIN;
									} else {
										token = tkOTHER;
									}
									break;
								}

							default:
								
								{
									token = tkOTHER;
									break;
								}

							}
							
							zIdx += nId - 1;
						} else {
							/* Operators and special symbols */							
							token = tkOTHER;
						}
						break;
					}

				}
				state = trans[state][token];
				zIdx++;
			}
			return (state == 1) ? 1 : 0;
			//return state==1;
		}

		/*
** This routine is the same as the sqlite3_complete() routine described
** above, except that the parameter is required to be UTF-16 encoded, not
** UTF-8.
*/public const int SQLITE_OK = 0;/* Successful result */
    public const int SQLITE_ERROR = 1;/* SQL error or missing database */
    public const int SQLITE_INTERNAL = 2;/* Internal logic error in SQLite */
    public const int SQLITE_PERM = 3;/* Access permission denied */
    public const int SQLITE_ABORT = 4;/* Callback routine requested an abort */
    public const int SQLITE_BUSY = 5;/* The database file is locked */
    public const int SQLITE_LOCKED = 6;/* A table in the database is locked */
    public const int SQLITE_NOMEM = 7;/* A malloc() failed */
    public const int SQLITE_READONLY = 8;/* Attempt to write a readonly database */
    public const int SQLITE_INTERRUPT = 9;/* Operation terminated by sqlite3_interrupt()*/
    public const int SQLITE_IOERR = 10;/* Some kind of disk I/O error occurred */
    public const int SQLITE_CORRUPT = 11;/* The database disk image is malformed */
    public const int SQLITE_NOTFOUND = 12;/* NOT USED. Table or record not found */
    public const int SQLITE_FULL = 13;/* Insertion failed because database is full */
    public const int SQLITE_CANTOPEN = 14;/* Unable to open the database file */
    public const int SQLITE_PROTOCOL = 15;/* NOT USED. Database lock protocol error */
    public const int SQLITE_EMPTY = 16;/* Database is empty */
    public const int SQLITE_SCHEMA = 17;/* The database schema changed */
    public const int SQLITE_TOOBIG = 18;/* String or BLOB exceeds size limit */
    public const int SQLITE_CONSTRAINT = 19;/* Abort due to constraint violation */
    public const int SQLITE_MISMATCH = 20;/* Data type mismatch */
    public const int SQLITE_MISUSE = 21;/* Library used incorrectly */
    public const int SQLITE_NOLFS = 22;/* Uses OS features not supported on host */
    public const int SQLITE_AUTH = 23;/* Authorization denied */
    public const int SQLITE_FORMAT = 24;/* Auxiliary database format error */
    public const int SQLITE_RANGE = 25;/* 2nd parameter to sqlite3_bind out of range */
    public const int SQLITE_NOTADB = 26;/* File opened that is not a database file */
    public const int SQLITE_ROW = 100;/* sqlite3_step() has another row ready */
    public const int SQLITE_DONE = 101;/* sqlite3_step() has finished executing */
static sqlite3_value sqlite3ValueNew( sqlite3 db )
    {
#if !SQLITE_POOL_MEM
      Mem p = new Mem();
#else
      Mem p = Pool.Allocate_Mem();//sqlite3DbMallocZero(db, sizeof(*p));
#endif
      //if ( p != null )
      //{
      p.flags = MEM_Null;
      p.type = SQLITE_NULL;
      p.db = db;
      //}
      return p;
    }
		
		int sqlite3_complete16 (string zSql)
		{
			//sqlite3_value pVal;
			int pVal;
			string zSql8;
			int rc = SQLITE_NOMEM;
			
			
//rc = sqlite3_initialize();
//if( rc !=0) return rc;
			
			pVal = sqlite3ValueNew (0);
			sqlite3ValueSetStr (pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
			zSql8 = sqlite3ValueText (pVal, SQLITE_UTF8);
			if (zSql8) {
				rc = sqlite3_complete (zSql8);
			} else {
				rc = SQLITE_NOMEM;
			}
			sqlite3ValueFree (pVal);
			return sqlite3ApiExit (0, rc);
		}
		
	}
	
}

